﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using POSGui.Classes;
using POSGui.Classes.BusinessLogic;
using POSGui.Clases.Entities;

namespace POSGui.Presentacion
{
    public struct DatosProducto
    {
        public String Codigo { get; set; }

        public String Nombre { get; set; }

        public Double PrecioPorUnidad { get; set; }

        public int Cantidad { get; set; }

        public Double PrecioconDescuento { get; set; }

        public Double PrecioTotal
        {
            get
            {
                if (PrecioconDescuento==0)
                {
                    return Cantidad * PrecioPorUnidad;
                }

                return PrecioconDescuento;
            }
        }
    }

    public partial class Ventas : Page
    {
        //private AppConfigReader appConfig = AppConfigReader.GetInstance();
        //private ERPSIA.IPointOfSaleServiceContract _webService = new ERPSIA.PointOfSaleServiceContractClient();
        List<DatosProducto> _carritoDeCompras;
        private int _rowCount;
        private ERPSIA.Item[] _itemList;
        private Sale _currentSale;
        private SystemVariable _systemVariable;
        private SaleStatus[] _saleStatuses;
        private ERPSIA.Document _newInvoice;
        WebServiceAgent userAgent;
                
        protected void Page_Load(object sender, EventArgs e)
        {

            //.. Codigo de verificacion de exiracion 
            Response.Cache.SetCacheability(HttpCacheability.NoCache);
            Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
            Response.Cache.SetNoStore();
            Response.AppendHeader("Pragma", "no-cache");
            if (Page.IsPostBack)
            {
                if (IsPageExpired())
                {
                    Response.Redirect(Constants.PAGE_MENU, true);
                    return;
                }
                Session["TimeStamp"] = DateTime.Now.ToString();
                ViewState["TimeStamp"] = DateTime.Now.ToString();
            }
            //..................

            // crea la lista de autocompletar
            CreateAutoCompleteList();

            //Instancias para manejo del documento 
            userAgent = (WebServiceAgent)Session[Constants.USER_WEB_SERVICE_CONN];

            _carritoDeCompras = CartManager.GetInstance(userAgent)._carritoDeCompras;
            _currentSale = CartManager.GetInstance(userAgent)._currentSale;
            _newInvoice = CartManager.GetInstance(userAgent).CheckCart();
            _currentSale.Products = CartManager.GetInstance(userAgent)._produc;


            //CartManager.GetInstance(userAgent).AddItem()
            
            // sube el carito de compras a la interfaz                      
            GridVenta.DataSource = _carritoDeCompras;
            GridVenta.DataBind();          
            
        }

        #region Métodos sobre el carrito

        //// <summary>
        /// Método que identifica si un producto ya se encuentra dentro de el carrito.
        /// </summary>
        /// <param name="productCode">Codigo del producto</param>
        /// <returns>Boolean que define si el producto con el codigo asociado esta dentro del carrito</returns>
        private Boolean ShoppingCartContains(String productCode)
        {
            if (_carritoDeCompras != null)
            {
                return _carritoDeCompras.Any(producto => producto.Codigo.Equals(productCode));
            }
            else
            {
                return false;
            }            
        }

        /// <summary>
        /// Método que agrega más articulos de un mismo producto dentro del carrito
        /// </summary>
        /// <param name="productCode">Código del producto</param>
        /// <param name="cantidad">Cantidad de articulos que agregar</param>
        private void AddMoreProducts(String productCode, int cantidad)
        {
            var indice = _carritoDeCompras.FindIndex(producto => producto.Codigo.Equals(productCode));
            var nuevosDatos = _carritoDeCompras[indice];
            nuevosDatos.Cantidad += cantidad;
            _carritoDeCompras[indice] = nuevosDatos;

            //Aumenta la cantidad en el carrito de venta
            _currentSale.Products[indice].Quantity += cantidad;
        }


        #endregion

        #region Métodos sobre el GUI

        /// <summary>
        /// Método que actualiza el grid a partir de la variable _carritoDeCompras,
        /// actualiza el valor de la variable en la variable global y
        /// actualiza el id del último postback.
        /// </summary>
        private void UpdateShoppingCart()
        {
            _rowCount = 0;
            GridVenta.DataSource = _carritoDeCompras;
            GridVenta.DataBind();
            // saca el subtotal
            var subtotal = _carritoDeCompras.Sum(carritoDeCompra => carritoDeCompra.PrecioTotal);
            SubtotalLabel.Text = string.Format("{0} {1:0.00}", Constants.MONEY_SYMBOL, subtotal);
            // saca los impuestos;
            var impuestos = subtotal * 0.13;
            ImpuestosLabel.Text = string.Format("{0} {1:0.00}", Constants.MONEY_SYMBOL, impuestos);
            // saca el total
            var total = subtotal + impuestos;
            TotalLabel.Text = string.Format("{0} {1:0.00}", Constants.MONEY_SYMBOL, total);
            _currentSale.Balance = subtotal;                    
        }

        #endregion

        #region Métodos de eventos del GUI

        /// <summary>
        /// Método que se dispara al ligar una nueva fila al grid de productos
        /// agrega los atributos de id y evento.
        /// </summary>
        protected void RowBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowType != DataControlRowType.DataRow ||
                (e.Row.RowState != DataControlRowState.Alternate && e.Row.RowState != DataControlRowState.Normal))
                return;

            e.Row.Attributes.Add("id", _rowCount.ToString());
            e.Row.Attributes.Add("onClick", "MarkRow(" + _rowCount + ");");

            var textoCantidadProducto = (TextBox)e.Row.FindControl("TextoCantidadProducto");
            textoCantidadProducto.Attributes.Remove("ID");
            textoCantidadProducto.Attributes.Add("ID", "textoCantidadProducto" + _rowCount);
            textoCantidadProducto.Attributes.Add("onFocus", "MarkRow(" + _rowCount + ");");

            var buttonDelete = (ImageButton)e.Row.FindControl("BotonDelete");
            buttonDelete.Attributes.Remove("ID");
            buttonDelete.Attributes.Add("ID", "botonDelete_" + _rowCount);

            _rowCount++;
        }


        /// <summary>
        /// Método que se dispara al ligar una nueva fila al grid de productos
        /// agrega los atributos de id y evento.
        /// </summary>
        protected void RowDeleted(object sender, EventArgs eventArgs)
        {
            try
            {
                if (string.IsNullOrEmpty(hidden3.Value)) return;
                var rowId = Convert.ToInt32(hidden3.Value);
                _carritoDeCompras.RemoveAt(rowId);
                var lista = _currentSale.Products.ToList();
                // borra el producto en la base de datos
                CartManager.GetInstance(userAgent).RemoveItem(lista[rowId].ProductId);                
                lista.RemoveAt(rowId);
                _currentSale.Products = lista;//.ToArray();
                UpdateShoppingCart();
            }
            catch (Exception)
            {
            }
        }


        /// <summary>
        /// Método que se dispara editar un producto de alguna fila.
        /// </summary>
        public void RowEdited(object sender, EventArgs eventArgs)
        {
            try
            {
                var systemVariable = (Session[Constants.SYSTEM_SESSION_VAR]);
                //if (systemVariable != null && ((SystemVariable)systemVariable).LastPostbackID.Equals(postbacktext.Value)) return;
                if (string.IsNullOrEmpty(hidden3.Value)) return;
                
                var response = hidden3.Value.Split('_');
                var currentRowString = response[0];
                var newQuantityString = response[1];
                var naturalNumberPattern=new Regex(Constants.REG_EX_NATURAL_NUMBER);

                if (naturalNumberPattern.IsMatch(newQuantityString))
                {
                    var rowId = Convert.ToInt32(currentRowString);
                    var oldQuantity = _currentSale.Products[rowId].Quantity;
                    var newQuantity = Convert.ToInt32(newQuantityString);
                    var quantityDifference = newQuantity - oldQuantity;
                    
                    //Borra el viejo
                    CartManager.GetInstance(userAgent).RemoveItem(_currentSale.Products[rowId].ProductId); 
                    //_webserviceWrapper.EraseProductsFromCart(_currentSale.SaleId, quantityDifference, _currentSale.Products[rowId].ProductCode);
                    _currentSale.Products[rowId].Quantity = newQuantity;
                    var producto = _carritoDeCompras[rowId];
                    producto.Cantidad = newQuantity;
                    _carritoDeCompras[rowId] = producto;
                    UpdateShoppingCart();
                }
            }
            catch (Exception)
            {
            }
        }

        /// <summary>
        /// Método que se dispara al presionar el botón "Finalizar Venta"
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void FinishCurrentSale(Object sender, EventArgs e)
        {
            if (_currentSale.Products.Count < 1) return;
            Response.Redirect(Constants.PAGE_PAYMENTS,true);   
            return;
        }

        /// <summary>
        /// Método que se dispara al presionar el boton "Agregar",
        /// agrega el nuevo producto en el grid.
        /// </summary>
        public void AddProduct(Object sender, EventArgs e)
        {
            //var systemVariable = (Session[Constants.SYSTEM_SESSION_VAR]);
            //if (systemVariable != null && ((SystemVariable)systemVariable).LastPostbackID.Equals(postbacktext.Value)) return;
            if (string.IsNullOrEmpty(TextoCantidad.Text) || string.IsNullOrEmpty(hidden1.Value)) return;
            var productCode = hidden1.Value;
            var cantidad = Convert.ToInt32(TextoCantidad.Text);
            var productExists = false;
            ERPSIA.Item item = null;

            // Si el producto ya esta en el carrito
            if (ShoppingCartContains(productCode))
            {
                productExists = true;
                AddMoreProducts(productCode, cantidad);
                UpdateShoppingCart();
                CartManager.GetInstance(userAgent).UpdateItem(productCode, cantidad);
                return;
            }
            // Si el producto no esta en el carrito
            else
            {
                //Busca por codigo el item en la lista de items cargada al inicio
                for (int i = 0; i < _itemList.Length; i++)
                {
                    if (_itemList[i].CodArticulo == productCode)
                    {
                        item = _itemList[i];                        
                    }
                }

                if (item != null)
                {
                    productExists = true;
                    ERPSIA.ItemStoreRoomInfo[] storeInfo = item.StoreInfo;
                    var producto = new DatosProducto
                    {
                        Codigo = item.CodArticulo,
                        Nombre = item.Descripción,
                        PrecioPorUnidad = storeInfo[0].CostoUnitario,
                        Cantidad = cantidad
                    };

                    var product = new Product {ProductCode = item.CodArticulo, ProductDescription = item.Comentario,
                    ProductCategoryId = 1, ProductInventoryId = 1, Price = storeInfo[0].CostoUnitario, Image = null, ProductId = item.Id,
                    ProductName = item.Descripción, ProductStatus = null, Quantity = cantidad};

                    // Guarda el producto en el carrito de la venta
                    /*product.Quantity = cantidad;
                    var productosVenta = _currentSale.Products.ToList();
                    productosVenta.Add(product);
                    _currentSale.Products = productosVenta.ToArray();*/
                    
                    if (_currentSale.Products == null)
                    {
                        _currentSale.Products = new List<Product>();
                    }

                    _currentSale.Products.Add(product);

                    // Saca la imagen de la base
                    //currentProductImage.ImageUrl = "~/Handler.ashx?id=" + producto.Codigo;

                    //Actualiza el panel lateral
                    detallesNombre.Text = producto.Nombre;
                    detallesPrecio.Text = string.Format("{0} {1:0.00} c/u", Constants.MONEY_SYMBOL,
                                                            producto.PrecioPorUnidad);
                    _carritoDeCompras.Add(producto);
                    UpdateShoppingCart();

                    var script = string.Format("MarkRow({0})",(_carritoDeCompras.Count - 1));
                    ExecuteScript(script);                    
                    //El producto no existe                    
                }                
                else
                {
                    ExecuteScript("alert('El producto ingresado no existe en el Sistema')");
                }
            }

            // añade un nuevo producto al carrito de la base de datos asincronicamente
            if (productExists)
            {                
                CartManager.GetInstance(userAgent).AddItem(userAgent, item, cantidad);
            }
        }

        /// <summary>
        /// Método que genera el arreglo para el autocompletar.
        /// </summary>
        private void CreateAutoCompleteList()
        {
            int storeId;
            WebServiceAgent userAgent = (WebServiceAgent)Session[Constants.USER_WEB_SERVICE_CONN];

            storeId = InventoryManager.GetInstance().GetCurrentStoreRoom(userAgent);
            ERPSIA.AuxiliarAccount[] _branchesList = userAgent.GetBranches();
            _itemList = userAgent.GetAvailableItems();
                        
            var script = "<script type=\"text/javascript\">custom_array = [";
           
            string[] _codList;
            
            if (_itemList != null)
            {
                _codList = new string[_itemList.Length];

                for (int i = 0; i < _itemList.Length; i++)
                {
                    _codList[i] = _itemList[i].CodArticulo;
                }
                    script = _codList.Aggregate(script, (current, code) => current + string.Format("\"{0}\",", code));
                script = script.TrimEnd(',');
            }
            script += "]; </script>";
            Page.ClientScript.RegisterClientScriptBlock(GetType(), "Prueba", script);
        }

        #endregion

        #region Métodos de carga y guardado de Ventas

        /// <summary>
        /// Metodo que permite salir del modulo de ventas guardardando la venta en curso
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ConfirmLeaveSavingSale(object sender, EventArgs e)
        {
            _currentSale.SaleStatus = _currentSale.Products.Count >= 1 ? _saleStatuses.ToList().Find(status => status.Status == Constants.STATUS_PAUSED) : _saleStatuses.ToList().Find(status => status.Status == Constants.STATUS_FINISHED);
            _currentSale.FinishDate = DateTime.Now;
            //WebserviceWrapper.GetInstance().EditSale(_currentSale);
            HttpResponse.RemoveOutputCacheItem("/Views/Ventas.aspx");
            Response.Redirect("Menu.aspx", true);
        }

        /// <summary>
        /// Evento que permite salir del modulo de ventas sin guardar la venta en curso
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ConfirmLeaveWithoutSavingSale(object sender, EventArgs e)
        {
            _currentSale.SaleStatus = _saleStatuses.ToList().Find(status => status.Status == Constants.STATUS_CANCELLED);
            _currentSale.FinishDate = DateTime.Now;
            //WebserviceWrapper.GetInstance().EditSale(_currentSale);
            HttpResponse.RemoveOutputCacheItem("/Views/Ventas.aspx");
            Response.Redirect("Menu.aspx", true);
        }      

        
        /// <summary>
        /// Metodo que permite ejecutar un script en la pagina
        /// </summary>
        /// <param name="script">Seccion de codigo javascript</param>
        public void ExecuteScript(string script)
        {
            Page.ClientScript.RegisterClientScriptBlock(GetType(), "Alerta",
                                                        string.Format(
                                                            "<script type=\"text/javascript\">{0}</script>",
                                                            script));
        }


        /// <summary>
        /// Permite crear una venta vacia lista para ser llenada
        /// </summary>
        /// <returns>Venta vacia</returns>
        private Sale CreateEmptySale()
        {
            var sale = new Sale
            {
                StartDate = DateTime.Now,
                //UserId = _systemVariable.User.UserId,
                SaleStatus = _saleStatuses.ToList().Find(status => status.Status == Constants.STATUS_INPROGRESS),
                FinishDate = DateTime.Now,
                //CashierId = _systemVariable.Cashier.CashierId,
                Currency = new ERPSIA.Currency(),
                Products = new List<Product>(),
            };
            return sale;
        }

        /// <summary>
        /// Metodo q permite saber si una pagina expiró o no
        /// </summary>
        /// <returns></returns>
        private bool IsPageExpired()
        {
            if (Session["TimeStamp"] == null ||
               ViewState["TimeStamp"] == null)
                return false;
            return Session["TimeStamp"] == ViewState["TimeStamp"];
        }
        #endregion
       

    }
}
